#pragma once

#include "vector.hpp"

namespace zuck
{
	template<typename T, typename Container = vector<T>>
	class stack {
	public:
		using container_type   = Container;
		using self             = stack<T, Container>;
		using value_type       = typename Container::value_type;
		using size_type        = typename Container::size_type;
		using reference        = value_type&;
		using const_reference  = value_type const&;
		using rvalue_reference = value_type&&;
	public:
		explicit stack() {}

		stack(Container const& data) : _data(data) {}

		stack(stack const& other) : _data(other._data) {}

		stack(stack&& other)noexcept : _data(zuck::move(other._data)) {}

		~stack() {}

		template<typename ...Args>
		void emplace(Args&&... args)           { _data.emplace_back(zuck::forward<Args>(args)...); }

		Container get_container()const          { return _data; }

		inline void push(value_type const& val) { _data.push_back(val); }

		inline void push(value_type&& val)      { _data.push_back(val); }

		inline value_type& top()                { return _data.back(); }

		inline void pop()                       { _data.pop_back(); }

		inline void swap(self& other)noexcept   {	_data.swap(other._data); }

		inline size_type size()const            { return _data.size(); }

		inline bool empty()const                { return _data.empty(); }

		inline stack& operator=(stack const& other) {
			_data = other._data;
			return *this;
		}

		inline stack& operator=(stack&& other)noexcept {
			_data = zuck::move(other._data);
			return *this;
		}

	private:
		Container _data{};
	};
}

